package com.dusk.util
{
    import com.game.manager.AnimationManager;
    import com.game.manager.GameSceneManager;
    import com.game.view.display.Texture;
    import com.game.view.display.TextureGroup;
    
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.GradientType;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.filters.ColorMatrixFilter;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    
    public class BitmapUtil extends UtilBase
    {
        
        /**
         * 创建纯色Bitmap
         * @param width 宽度 默认50
         * @param height 高度 默认50
         * @param color 颜色 默认红色
         * @return Bitmap
         */
        public static function createPureBitmap(width:int = 50, height:int = 50, color:uint = 0xFF0000):Bitmap
        {
            return new Bitmap(new BitmapData(width, height, false, color), "auto", true);
        }
        
        /**
         * 按照一定的大小切分一行图片为Texture
         * @param tarBmd 目标图片
         * @param rect 切分矩形
         * @return 包含所有内容的TextureGroup
         */
        public static function buildRows(tarBmd:BitmapData, rect:Rectangle):TextureGroup
        {
            var totalLength:int = Math.ceil(tarBmd.width / rect.width);
            var group:TextureGroup = new TextureGroup();
            for (var idx:int = 0; idx < totalLength; idx++)
            {
                rect.x = idx * rect.width;
                var bmd:BitmapData = new BitmapData(rect.width, rect.height, true, 0);
                bmd.copyPixels(tarBmd, rect, new Point());
                group.addTexture(new Texture(bmd));
            }
            return group;
        }
        
        /**
         * 按照一定的大小切分一列图片为Texture
         * @param tarBmd 目标图片
         * @param rect 切分矩形
         * @return 包含所有内容的TextureGroup
         */
        public static function buildCols(tarBmd:BitmapData, rect:Rectangle):TextureGroup
        {
            var totalLength:int = Math.ceil(tarBmd.width / rect.height);
            var group:TextureGroup = new TextureGroup();
            for (var idx:int = 0; idx < totalLength; idx++)
            {
                rect.y = idx * rect.height;
                var bmd:BitmapData = new BitmapData(rect.width, rect.height, true, 0);
                bmd.copyPixels(tarBmd, rect, new Point());
                group.addTexture(new Texture(bmd));
            }
            return group;
        }
        
        /**
         * 构建行列Texture,传入行列数或者是矩形，矩形会覆盖行列数
         * 注意在末端行可能出现纯色块的Texture
         * @param bitmapData
         * @param columns 指定一行数量
         * @param rows 指定一列数量
         * @param rectangle 指定切割矩阵
         * @return 包含所有内容的TextureGroup
         * @example buildRowCol(bitmapData, 3, 3);
         * @example buildRowCol(bitmapData, 3, 3, new Rectangle(0, 0, 100, 100));
         */
        public static function buildRowCol(bitmapData:BitmapData, columns:int, rows:int, rectangle:Rectangle = null):TextureGroup
        {
            var group:TextureGroup = new TextureGroup();
            var cellRectangle:Rectangle = new Rectangle();
            cellRectangle.width = bitmapData.width / columns;
            cellRectangle.height = bitmapData.height / rows;
            
            if (rectangle != null)
            {
                cellRectangle = rectangle;
            }
            
            for (var rowIndex:int = 0; rowIndex < rows; rowIndex++)
            {
                cellRectangle.y = rowIndex * cellRectangle.height;
                
                for (var colIndex:int = 0; colIndex < columns; colIndex++)
                {
                    cellRectangle.x = colIndex * cellRectangle.width;
                    var cellBitmapData:BitmapData = new BitmapData(cellRectangle.width, cellRectangle.height, true, 0);
                    cellBitmapData.copyPixels(bitmapData, cellRectangle, new Point());
                    group.addTexture(new Texture(cellBitmapData));
                }
            }
            
            return group;
        }
        
        /**
         * 按目标大小缩放位图
         */
        public static function scaleToTargetSize(bm:Bitmap, width:int, height:int):Bitmap
        {
            bm.width = width;
            bm.height = height;
            return bm;
        }
        
        /**
         * 旋转位图
         * @param bm 原始位图，转换后会被释放
         * @param angle 角度，采用角度制，如90度则传入90，代表顺时针旋转度数
         * @param isDispose 是否释放原始位图
         */
        public static function rotate(bm:BitmapData, angle:Number, isDispose:Boolean = true):BitmapData
        {
            var newWidth:int;
            var newHeight:int;
            var angleRadian:Number = angle * Math.PI / 180;
            if (angle % 180 == 0)
            {
                newWidth = bm.width;
                newHeight = bm.height;
            }
            else if (angle % 90 == 0)
            {
                newWidth = bm.height;
                newHeight = bm.width;
            }
            else
            {
                newWidth = Math.abs(Math.cos(angleRadian) * bm.width) + Math.abs(Math.sin(angleRadian) * bm.height);
                newHeight = Math.abs(Math.sin(angleRadian) * bm.width) + Math.abs(Math.cos(angleRadian) * bm.height);
            }
            var newBmd:BitmapData = new BitmapData(newWidth, newHeight, true, 0);
            var matrix:Matrix = new Matrix();
            matrix.translate(-bm.width / 2, -bm.height / 2);
            matrix.rotate(angleRadian); //旋转
            matrix.translate(bm.height / 2, bm.width / 2);
            newBmd.draw(bm, matrix);
            if (isDispose) bm.dispose();
            return newBmd;
        }
        
        /**
         * RGB转灰度
         * @param bmd
         * @return
         */
        public static function rgb2gray(bmd:BitmapData):BitmapData
        {
            var rLum:Number = 0.3;
            var gLum:Number = 0.59;
            var bLum:Number = 0.11;
            var matrix:Array = [
                rLum, gLum, bLum, 0, 0,
                rLum, gLum, bLum, 0, 0,
                rLum, gLum, bLum, 0, 0,
                0, 0, 0, 1, 0
            ];
            var grayscaleFilter:ColorMatrixFilter = new ColorMatrixFilter(matrix);
            bmd.applyFilter(bmd, bmd.rect, new Point(), grayscaleFilter);
            return bmd;
        }
        
        /**
         * 添加边框，注意会增加图像大小
         * @param bmd 位图数据
         * @param color 边框颜色
         * @param w 边框宽度
         */
        public static function wrapBorder(bmd:BitmapData, color:uint = 0xFF0000, w:int = 3):BitmapData
        {
            var data:BitmapData = new BitmapData(bmd.width + 2 * w, bmd.height + 2 * w, bmd.transparent, color | 0xFF000000);
            var destPoint:Point = new Point(w, w);
            data.copyPixels(bmd, bmd.rect, destPoint);
            bmd.dispose();
            return data;
        }
        
        /**
         * 给图像添加圆角
         */
        public static function wrapRoundRect(bmd:BitmapData, cornerRadius:int = 5):BitmapData
        {
            var newBmd:BitmapData = new BitmapData(bmd.width, bmd.height, true, 0x00000000);
            var shape:Shape = new Shape();
            shape.graphics.beginFill(0xFFFFFF);
            shape.graphics.drawRoundRect(0, 0, bmd.width, bmd.height, cornerRadius, cornerRadius);
            shape.graphics.endFill();
            var mask:BitmapData = new BitmapData(bmd.width, bmd.height, true, 0x00000000);
            mask.draw(shape);
            newBmd.copyPixels(bmd, bmd.rect, new Point(0, 0), mask, new Point(0, 0), true);
            return newBmd;
        }
        
        /**
         * 裁剪透明区域
         * @param bmd 位图数据
         * @return 位图数据
         */
        public static function cropTransparentRegion(bmd:BitmapData):BitmapData
        {
            var rect:Rectangle = getOpaqueRegion(bmd);
            return cropImage(bmd, rect, true);
        }
        
        /**
         * 获取最小不透明区域
         */
        public static function getOpaqueRegion(bmd:BitmapData):Rectangle
        {
            var rect:Rectangle = bmd.getColorBoundsRect(0xFF000000, 0x00000000, false);
            if (rect.isEmpty())
            {
                return new Rectangle(0, 0, bmd.width, bmd.height);
            }
            return rect;
        }
        
        /**
         * 按照一定的区域裁剪图像
         * @param bmd 原始位图数据
         * @param rect 裁切区域
         * @param isDispose 是否释放原图像
         *
         * 在裁切空白区域的时候建议释放原图像，进行大图纹理分析的时候不要释放原图像
         */
        public static function cropImage(bmd:BitmapData, rect:Rectangle, isDispose:Boolean = true):BitmapData
        {
            try
            {
                var bd:BitmapData = new BitmapData(rect.width, rect.height);
                bd.copyPixels(bmd, rect, new Point());
                if (isDispose) bmd.dispose();
                return bd;
            } catch (e:ArgumentError)
            {
                if (e.errorID == 2015)
                {
                    GameSceneManager.getIns().switchScene(GameSceneManager.GAME_MAP);
                    AnimationManager.clearAllCache();
                    return bmd;
                }
                return null;
            }
        }
        
        public static function drawSpriteToBitmap(sp:Sprite, crop:Boolean = true):BitmapData
        {
            var prvSpace:Sprite = new Sprite();
            sp.x = sp.y = 0;
            prvSpace.addChild(sp);
            var rect:Rectangle = sp.getBounds(prvSpace);
            var bmd:BitmapData = new BitmapData(rect.width, rect.height, true, 0);
            bmd.draw(prvSpace, new Matrix(1, 0, 0, 1, -rect.x, -rect.y), null, null, null, true);
            if (crop)
            {
                return cropTransparentRegion(bmd);
            }
            return bmd;
        }
        
        /**
         * 使用位处理对图片应用渐变
         * @param bmd 位图数据
         * @param colors 渐变颜色数组
         * @param alphas 渐变透明度
         * @param ratios 渐变比例
         * @param gradientType GradientType.LINEAR 线性渐变 或 GradientType.RADIAL 圆形渐变
         * @param matrix 渐变方向矩阵
         * @return 位图数据
         *
         * 原理是通过新建一个已经渐变好的图像，然后把原图中非透明的区域进行颜色覆盖
         *
         * 此API不如直接对Bitmap应用渐变滤镜效果好
         */
        public static function applyGradientToBitmapData(bmd:BitmapData, colors:Array, alphas:Array, ratios:Array, gradientType:String = GradientType.LINEAR, matrix:Matrix = null):BitmapData
        {
            // 如果没有提供矩阵，则创建一个默认的渐变矩阵
            if (matrix == null)
            {
                matrix = new Matrix();
                matrix.createGradientBox(bmd.width, bmd.height, Math.PI / 2, 0, 0);
            }
            
            // 创建一个 Shape 来绘制渐变
            var shape:Shape = new Shape();
            shape.graphics.beginGradientFill(gradientType, colors, alphas, ratios, matrix);
            shape.graphics.drawRect(0, 0, bmd.width, bmd.height);
            shape.graphics.endFill();
            
            // 将渐变填充绘制到一个新的 BitmapData 对象中
            var gradientBitmapData:BitmapData = new BitmapData(bmd.width, bmd.height, true, 0x00000000);
            gradientBitmapData.draw(shape);
            
            // 创建一个新的 BitmapData 来存储最终结果
            var resultBitmapData:BitmapData = new BitmapData(bmd.width, bmd.height, true, 0x00000000);
            
            // 遍历原始 BitmapData 的每个像素，应用渐变色
            for (var y:int = 0; y < bmd.height; y++)
            {
                for (var x:int = 0; x < bmd.width; x++)
                {
                    var pixel:uint = bmd.getPixel32(x, y);
                    var alpha:uint = pixel >> 24 & 0xFF;
                    // 仅对非透明像素应用渐变色
                    if (alpha <= 0)
                    {
                        continue;
                    }
                    var gradientPixel:uint = gradientBitmapData.getPixel32(x, y);
                    var gradientColor:uint = gradientPixel & 0x00FFFFFF;
                    resultBitmapData.setPixel32(x, y, (alpha << 24) | gradientColor);
                }
            }
            // 返回结果 BitmapData
            return resultBitmapData;
        }
        
        /**
         * 分析plist文件为BitmapClip
         * @param plistData String或者xml数据
         * @param bmd 大图数据
         * @return
         */
        public static function analysePlistToTextureGroup(plistData:*, bmd:BitmapData):TextureGroup
        {
            var plistXML:XML = plistData is String ? XML(plistData) : plistData;
            plistData = TexturePackerParser.xml2Obj(plistXML);
            
            var frameQueue:Object = plistData.frames;
            var keys:Array = TexturePackerParser.sortFrameKey(frameQueue);
            var tsGroup:TextureGroup = new TextureGroup();
            for each(var key:String in keys)
            {
                var obj:Object = frameQueue[key];
                var arr:Array;
                //裁切区域，frame为格式2，textureRect为格式3
                arr = TexturePackerParser.args2arr(obj.frame || obj.textureRect)
                var frameRect:Rectangle = new Rectangle(arr[0], arr[1], arr[2], arr[3]);
                //偏移，offset为格式2，spriteOffset为格式3
                arr = TexturePackerParser.args2arr(obj.offset || obj.spriteOffset)
                var off:Point = new Point(arr[0], arr[1]);
                //源图片大小，sourceSize为格式2，spriteSize为格式3
                arr = TexturePackerParser.args2arr(obj.sourceSize || obj.spriteSourceSize);
                var size:Point = new Point(arr[0], arr[1]);
                //是否旋转，rotated为格式2，textureRotated为格式3
                var rotated:Boolean = obj.hasOwnProperty("rotated") ? obj.rotated : obj.textureRotated;
                
                tsGroup.addTexture(TexturePackerParser.parseBmd2Texture(bmd, frameRect, off, size, rotated));
            }
            tsGroup.clearSameKeyFrame();
            return tsGroup;
        }
        
    }
}

import com.dusk.util.BitmapUtil;
import com.dusk.util.UtilBase;
import com.game.view.display.Texture;

import flash.display.BitmapData;

import flash.geom.Point;
import flash.geom.Rectangle;

class TexturePackerParser
{
    
    /**
     * 解析plist文件
     * @param xmlData xml 数据
     * @return 解析后的对象，键顺序是乱序，要自己调整
     */
    public static function xml2Obj(xmlData:XML):Object
    {
        var obj:Object = {};
        if (xmlData.child("key").length() == 0)
        {
            xmlData = new XML(xmlData.child("dict")[0]);
        }
        for (var i:int = 0; i < xmlData.children().length(); i += 2)
        {
            var key:String = xmlData.children()[i].toString();
            var valueNode:XML = xmlData.children()[i + 1];
            var value:*;
            if (valueNode.name() == "string") value = valueNode.toString();
            else if (valueNode.name() == "false") value = false;
            else if (valueNode.name() == "true") value = true;
                    else if(valueNode.name() == "integer") value = parseInt(valueNode.toString());
            else if (valueNode.name() == "array") value = valueNode.toString().split(",");
            else if (valueNode.name() == "dict")
            {
                //递归处理
                value = xml2Obj(valueNode);
            }
            else value = null;
            obj[key] = value;
        }
        return obj;
    }
    
    /**
     * 由于键的最后帧数没有补零对齐，所以排序需要特殊处理
     * @param obj 所有键值都是帧序列名称的对象
     * @return 排序后的键数组
     */
    public static function sortFrameKey(obj:Object):Array
    {
        /**
         * 自定义排序函数
         */
        function customSort(a:String, b:String):int
        {
            const regExp:RegExp = /(\d+)/g;
            var aParts:Array = a.match(regExp);
            var bParts:Array = b.match(regExp);
            for (var i:int = 0; i < Math.min(aParts.length, bParts.length); i++)
            {
                var aNum:int = int(aParts[i]);
                var bNum:int = int(bParts[i]);
                if (aNum < bNum) return -1;
                else if (aNum > bNum) return 1;
            }
            // 如果前面的部分都相等，按长度排序
            if (aParts.length < bParts.length) return -1;
            else if (aParts.length > bParts.length) return 1;
            return 0;
        }
        
        var keys:Array = UtilBase.getAllKeys(obj);
        return keys.sort(customSort);
    }
    
    /**
     * 对于其特殊的字符串格式进行解析得到参数
     * @param str 类似这样的字符串 => "{{100, 300},{833, 200}}"
     * @return 数组 => 100,300,833,200
     */
    public static function args2arr(str:String):Array
    {
        while (str.indexOf("{") + str.indexOf("}") > -2)
        {
            str = str.replace("{", "").replace("}", "");
        }
        return str.split(",");
    }
    
    /**
     * 根据参数裁切图片
     * @param sourceBitmapData 大图
     * @param frameRect 需要裁切的地方相对于大图的坐标，当rotate为true时会自动转换
     * @param offset 纹理偏移，会根据这个偏移量自动计算注册点
     * @param sourceSize 精灵表的原始精灵尺寸
     * @param rotated 是否旋转
     * @return
     */
    public static function parseBmd2Texture(
            sourceBitmapData:BitmapData,
            
            frameRect:Rectangle,
            offset:Point,
            sourceSize:Point,
            rotated:Boolean
    ):Texture
    {
        var tex:Texture = new Texture();
        var cropRect:Rectangle = frameRect.clone();
        if (rotated) cropRect = new Rectangle(frameRect.x, frameRect.y, cropRect.height, cropRect.width);
        var cropBmd:BitmapData = new BitmapData(cropRect.width, cropRect.height, true, 0x00000000);
        cropBmd.copyPixels(sourceBitmapData, cropRect, new Point(0, 0));
        if (rotated) cropBmd = BitmapUtil.rotate(cropBmd, -90);
        tex.region = new Rectangle((sourceSize.x - frameRect.width) / 2 + offset.x,
                (sourceSize.y - frameRect.height) / 2 - offset.y,
                1,
                1);
        tex.content = cropBmd;
        return tex;
    }
}